#include<sys\\stat.h>
#include<sys\\types.h>
#include<direct.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>

#define mSol 1
#define mTerra 3.003167261575587e-6
#define mJupiter 9.543512141169373e-4
#define mSaturno 2.694686038912071e-4


#define PI 3.141592653589793
#define G 4*pow(PI,2)
#define perielioTerra 0.983235919814466
#define vPerielioTerra 6.389661159796174
#define perielioSaturno 9.041238312224186
#define vPerielioSaturno 2.147466180479533
#define excentricidadeTerra 0.0167

void inicializacao(void);
void condicoesIniciais(void);
void keplerT(void);
void keplerTd(void);
void estrelaDupla(void);
void criarArquivos(void);
void escreverArquivos(void);
void ruth(void);
void Fr(double *dx, double *p, double m,int dimensao);
void ruthR(int dimensao, double *r,double dt,double *dx,double c);
void calcularDistancia(double *r,double *distancia, int dimensao);
void Fp(double *dx,double *r,double *distancia,int dimensao);
void ruthP(int dimensao, double *p,double dt,double *dx,double d);
void calcularTempo();
void fecharArquivos(void);

double  m,M, *r, *p,   tFinal,    dt,     c[4]  ,  d[4] , expoente, temp,*dx, *distancia,tempo=0;
int dimensao, n, T, corpos,intervaloGravacao,minutos=0,segundos=0,horas=0,tempo2=0;
char *exemplo,*aux,*SO;
//2*N+1
FILE *f[3];
clock_t inicio,fim,total;

int main(int argc, char *argv[])
{
	inicio=clock();

	SO=argv[1];
	intervaloGravacao=atoi(argv[2]);
	tFinal=atof(argv[3]);
	n=atof(argv[4]);

	inicializacao();

	criarArquivos();

	escreverArquivos();

	ruth();

	calcularTempo();

	fecharArquivos();

	return 0;
}

void inicializacao(void)
{
	dimensao=2;
	corpos=1;
	T=(int)pow(2.0,n)+1;
	dt=tFinal/(T-1);

	condicoesIniciais();

	//coeficientes do metodo
	expoente=1.0/3;
	temp=2-pow(2,expoente);
	temp=1/temp;

	c[0]=temp/2;
	c[3]=c[0];
	c[1]=temp/2;
	c[1]=c[1]*(1-pow(2,expoente));
	c[2]=c[1];
	d[0]=temp;
	d[2]=temp;
	d[1]=temp;
	d[1]=-1*d[1]*pow(2,expoente);
	d[3]=0;
}

void condicoesIniciais(void)
{
	r =(double *)calloc(dimensao, sizeof(double));
	p =(double *)calloc(dimensao, sizeof(double));
	dx =(double *)calloc(dimensao, sizeof(double));
	distancia =(double *)calloc(2 ,sizeof(double));

	//keplerTd();
	//keplerS();
	keplerT();
	//estrelaDupla();
}

void keplerT(void)
{
	exemplo="C:\\dados\\";
	mkdir(exemplo);
	exemplo="C:\\dados\\kepler\\";
	mkdir(exemplo);

	M=mSol;
	m=mTerra;
	r[0]=perielioTerra;
	p[1]=mTerra*vPerielioTerra;
}

void estrelaDupla(void)
{
	exemplo="C:\\dados\\";
	mkdir(exemplo);
	exemplo="C:\\dados\\keplerED\\";
	mkdir(exemplo);

	M=2*mSol;
	m=0.5;
	r[0]=2;
	p[1]=m*2*PI;
}

void keplerTd(void)
{
	exemplo="C:\\dados\\";
	mkdir(exemplo);
	exemplo="C:\\dados\\keplerTd\\";
	mkdir(exemplo);

	M=mSol;
	m=mTerra;
	r[0]=perielioTerra;
	p[1]=mTerra*vPerielioTerra;
	r[0]+=1.0;
	r[1]+=1.0;
}

void keplerS(void)
{
	exemplo="C:\\dados\\";
	mkdir(exemplo);
	exemplo="C:\\dados\\keplerSaturno\\";
	mkdir(exemplo);

	M=mSol;
	m=mSaturno;
	//perielio de Saturno
	r[0]=perielioSaturno;
	//momento no perielio de Saturno
	p[1]=mSaturno*vPerielioSaturno;
}

void criarArquivos(void)
{
	char *raiz,*diretorio,*aux,*barra;
	raiz=(char*)calloc(100,sizeof(char));
	aux=(char*)calloc(100,sizeof(char));
	diretorio=(char*)calloc(100,sizeof(char));

	if(!strcmp(SO,"w"))
	{
		barra="\\";
	}
	if(!strcmp(SO,"l"))
	{
		barra="/";
	}

	strcpy(raiz,exemplo);
	//strcat(raiz,barra);
	//mkdir(raiz,S_IRWXU);
	mkdir(raiz);
	sprintf(aux,"%0.0lf",tFinal);
	strcat(raiz,aux);
	sprintf(aux,"%d",n);
	strcat(raiz,barra);
	//mkdir(raiz,S_IRWXU);
	mkdir(raiz);
	strcat(raiz,aux);
	strcat(raiz,barra);
	//mkdir(raiz,S_IRWXU);
	mkdir(raiz);

	strcpy(diretorio,raiz);
	strcat(diretorio,"r.txt");
	f[0] = fopen(diretorio,"w");
	if(f[0] == NULL)
	{
		printf("Erro ao abrir arquivo posicao!!!\n");
		exit(1);
	}
	strcpy(diretorio,raiz);
	strcat(diretorio,"p.txt");
	f[1] = fopen(diretorio,"w");
	if(f[1] == NULL)
	{
		printf("Erro ao abrir arquivo momento!!!\n");
		exit(1);
	}

	strcpy(diretorio,raiz);
	strcat(diretorio,"tempo.txt");
	f[2*corpos] = fopen(diretorio,"w");
	if(f[2*corpos] == NULL)
	{
		printf("Erro ao abrir arquivo tempo!!!\n");
		exit(1);
	}


	free(aux);
	free(raiz);
	free(diretorio);
}

void escreverArquivos(void)
{
	int j,k;
	char aux[100];

	for(k=0;k<corpos;k++)
	{
		for(j=0;j<dimensao;j++)
		{
			//arquivo txt
			//posicao
			sprintf(aux,"%0.15lf ",r[k*dimensao+j]);
			fputs(aux,f[k]);
			//momento
			sprintf(aux,"%0.15lf ",p[k*dimensao+j]);
			fputs(aux,f[k+corpos]);
		}
		fputs("\n",f[k]);
		fputs("\n",f[k+corpos]);
	}
}

void ruth(void)
{
	int i,j;

	for(i=1;i<T;i++)
	{
		for(j=0;j<4;j++)
		{
			Fr(dx,p,m,dimensao);
			ruthR(dimensao,r,dt,dx,c[j]);
			calcularDistancia(r,distancia,dimensao);
			Fp(dx,r,distancia,dimensao);
			ruthP(dimensao,p,dt,dx,d[j]);
		}
		if(i%intervaloGravacao==0)
		{
			escreverArquivos();
		}
	}
}

void Fr(double *dx, double *p, double m,int dimensao)
{
	int i;

	for(i=0;i<dimensao;i++)
	{
		dx[i]= p[i]/m;
	}
}

void ruthR(int dimensao, double *r,double dt,double *dx,double c)
{
	int i;

	for(i=0;i<dimensao;i++)
	{
		r[i]=r[i]+dt*c*dx[i];
	}
}

void calcularDistancia(double *r,double *distancia, int dimensao)
{
	int i;

	distancia[0]=0;
	for(i=0;i<dimensao;i++)
	{
		distancia[0]+=pow(r[i],2);
	}
	distancia[0]=sqrt(distancia[0]);
}

void Fp(double *dx,double *r,double *distancia,int dimensao)
{
	int i;

	for(i=0;i<dimensao;i++)
	{
		dx[i]=0;
		dx[i]= dx[i] -(4*pow(PI,2)*m*M*(r[i]))/(double)(pow(distancia[0],3));
	}
}

void ruthP(int dimensao, double *p,double dt,double *dx,double d)
{
	int i;

	for(i=0;i<dimensao;i++)
	{
		p[i]=p[i]+dt*d*dx[i];
	}
}

void calcularTempo()
{
	fim=clock();
	total=fim-inicio;
	tempo=(double)total/CLOCKS_PER_SEC;
	tempo2=(int)tempo;
	horas=(tempo2/3600);
	minutos=(tempo2/60)-horas*60;
	segundos=(tempo2 % 60);
	printf("%d h %d min %d s\n",horas, minutos ,segundos);
	printf("%lf \n",tempo);
}

void fecharArquivos(void)
{
	char aux[100];

	int NFiles= corpos*dimensao+1,i;
	sprintf(aux,"tempo de execucao= %0.3lf s",tempo);
	strcat(aux,"\n");
	fputs(aux,f[NFiles-1]);

	for(i=0;i<NFiles;i++)
	{
		fclose(f[i]);
	}
}
